Generated code - Transactions, Adapter
	Preface
	Adapter supports, like SelfServicing, both COM+ and ADO.NET transactions. Below is explained how ADO.NET transactions are used in Adapter, and how COM+ 
	transactions can be used in Adapter. COM+, or better: enterprise services, offers more than just transactional behavior. You can also use COM+ to enable Just-In-Time
	activation (JIT) or object pooling. The COM+ transaction section below has a small discussion on that as well. 
	Adapter automatically uses ADO.NET transactions for recursive saves and save/delete actions for collections of entities, unless the adapter object is owned by a 
	ComPlusAdapterContext object. 
 
	
Normal native database transactions
	(It's assumed the database used supports transactions, which is the case in all major databases like SqlServer). 
	Native database transactions are provided by ADO.NET; it's a part of an ADO.NET connection object.  
	Database statements can be executed within the same transaction by using the same connection object. 
	LLBLGen Pro's native database transactions are implemented in the DataAccessAdapter object. You can simply start a transaction using a DataAccessAdapter
	object, execute methods of that DataAccessAdapter object and rollback or commit the transaction. Because the transactional code is inside the DataAccessAdapter,
	every method of the DataAccessAdapter object you call after you've started a transaction is ran inside that transaction, including stored procedure calls, entity fetches,
	entity collection saves etc. This greatly simplifies the programming of code using the variety of functionality the DataAccessAdapter object offers. You don't have to
	add entity objects or entity collection objects to the DataAccessAdapter object to make them participate in the transaction, just call a DataAccessAdapter method and
	it's inside the transaction of that particular DataAccessAdapter object. If you wish to run a particular action outside of a transaction, create a new DataAccessAdapter
	object for that particular action. 
	
	
	
    	
        	  Note:
         | 
    
    
        | 
        	If you start a new transaction by calling StartTransaction() the connection is kept open until Rollback() or Commit() is called. 
         | 
    
	An example will help illustrate the usage of the transaction functionality of the DataAccessAdapter object. We're going to update 2 different entities in one transaction.
	For this example, it has to be done in one go, as an atomic unit, and therefore requires a transaction. The data is rather bogus, it's for illustration purposes only).
  
  
    // [C#]
// create adapter for fetching and the transaction. 
DataAccessAdapter adapter = new DataAccessAdapter();
// start the transaction.
adapter.StartTransaction(IsolationLevel.ReadCommitted, "TwoUpates");
try
{
	// fetch the two entities
	CustomerEntity customer = new CustomerEntity("CHOPS");
	OrderEntity order = new OrderEntity(10254);
	adapter.FetchEntity(customer);
	adapter.FetchEntity(order);
	
	// alter the entities
	customer.Fax = "12345678";
	order.Freight = 12;
	
	// save the two entities again.
	adapter.SaveEntity(customer);
	adapter.SaveEntity(order);
	
	// done
	adapter.Commit();
}
catch
{
	// abort, roll back the transaction
	adapter.Rollback();
	// bubble up exception
	throw;
}
finally
{
	// clean up. Necessary action.
	adapter.Dispose();
} 
    ' [VB.NET]
' create adapter for fetching and the transaction. 
Dim adapter As New DataAccessAdapter()
' start the transaction.
adapter.StartTransaction(IsolationLevel.ReadCommitted, "TwoUpates")
Try
	' fetch the two entities
	Dim customer As New CustomerEntity("CHOPS")
	Dim order As New OrderEntity(10254)
	adapter.FetchEntity(customer)
	adapter.FetchEntity(order)
	
	' alter the entities
	customer.Fax = "12345678"
	order.Freight = 12
	
	' save the two entities again.
	adapter.SaveEntity(customer)
	adapter.SaveEntity(order)
	
	' done
	adapter.Commit()
Catch
	' abort, roll back the transaction
	adapter.Rollback()
	' bubble up exception
	Throw
Finally
	' clean up. Necessary action.
	adapter.Dispose()
End Try 
   
 
	First a DataAccessAdapter object is created and a transaction is started. As soon as you start the transaction, a database connection is open and usable. This is 
	also the reason why you 
must include a final clause and call Dispose() when the DataAccessAdapter object is no longer needed. 
	This is good practice anyway. 
	The code is the same as if you didn't start a transaction, except for the Commit() / Rollback() combination at the end.  Simply start a transaction, call the methods 
	you want to call, and if no exceptions are caught, Commit(), otherwise Rollback().
	
	It's best practice to embed the usage of a transaction in a try/catch/finally statement as it is done in the example above.  
	This ensures that if something fails during the usage of the transaction, everything is rolled back or, at the end, everything is committed correctly.
	
Transaction savepoints
	Most databases support transaction savepoints. Transaction savepoints make it possible to do fine grained transaction control on a semi-nested level. This can
	be required as ADO.NET doesn't support nested transactions. Savepoints let you define a point in a transaction to which you can roll back, without rolling back
	the complete transaction. This can be handy if you have saved some entities in a transaction which were saved OK, and another one fails, however the failure of that
	save shouldn't terminate the whole transaction, just roll back the transaction to a given point in the transaction. LLBLGen Pro offers you the ability to define
	savepoints in a transaction. The following example illustrates the savepoint functionality. It first saves a new address entity and after that it saves the
	transaction. It then saves a new customer entity but takes into account that this can fail. If it does, it should roll back to the savepoint set, it should thus
	not rollback the complete transaction. Consider the example an illustration for the feature, in your code, the code utilizing the transaction will probably span
	several classes and methods. Savepoints are not supported with COM+ transactions.
  
  
    //C#
DataAccessAdapter adapter = new DataAccessAdapter();
try
{
	adapter.StartTransaction(IsolationLevel.ReadCommitted, "SavepointRollback");
	// first save a new address
	AddressEntity newAddress = new AddressEntity();
	// ... fill the address entity with values
	// save it.
	adapter.SaveEntity(newAddress, true);
	// save the transaction
	adapter.SaveTransaction("SavepointAddress");
	// save a new customer
	CustomerEntity newCustomer = new CustomerEntity();
	// ... fill the customer entity with values
	newCustomer.VisitingAddress = newAddress;
	newCustomer.BillingAddress = newAddress;
	
	try
	{
		adapter.SaveEntity(newCustomer, true);
	}
	catch(Exception ex)
	{
		// something was wrong. 
		// ... handle ex here.
		// roll back to savepoint.
		adapter.Rollback("SavepointAddress");
	}
	
	// commit the transaction. If the customer save failed, 
	// only address is saved, otherwise both.
	adapter.Commit();
}
catch
{
	// fatal error, roll back everything
	adapter.Rollback();
	throw;
}
finally
{
	adapter.Dispose();
}
 
    ' VB.NET
Dim adapter As new DataAccessAdapter()
Try
	adapter.StartTransaction(IsolationLevel.ReadCommitted, "SavepointRollback")
	' first save a new address
	Dim newAddress As New AddressEntity()
	' ... fill the address entity with values
	' save it.
	adapter.SaveEntity(newAddress, True)
	' save the transaction
	adapter.SaveTransaction("SavepointAddress")
	' save a new customer
	Dim newCustomer As New CustomerEntity()
	' ... fill the customer entity with values
	newCustomer.VisitingAddress = newAddress
	newCustomer.BillingAddress = newAddress
		
	Try
		adapter.SaveEntity(newCustomer, True)
	Catch(Exception ex)
		' something was wrong. 
		' ... handle ex here.
		' roll back to savepoint.
		adapter.Rollback("SavepointAddress")
	End Try
	
	' commit the transaction. If the customer save failed, 
	' only address is saved, otherwise both.
	adapter.Commit()
Catch
	// fatal error, roll back everything
	adapter.Rollback()
	Throw
Finally
	adapter.Dispose()
End Try
 
   
 
	
	
    	
        	  Note:
         | 
    
    
        | 
        	Microsoft Access doesn't support savepoints in transactions, so this feature is not supported when you use LLBLGen Pro with MS Access.
         | 
    
	
COM+ transactions
	LLBLGen Pro supports COM+ transactions for adapter as well through a special COM+ class called ComPlusAdapterContext. This class is generated in the DataAccessAdapter
	class file and is thus located in the database specific project. The ComPlusAdapterContext class is actually a thin wrapper class which implements abstract methods
	in its base class ComPlusAdapterContextBase. The ComPlusAdapterContext class embeds a DataAccessAdapter object which will act the same as a normal DataAccessAdapter
	object, only this time it will utilize the COM+ context held by the ComPlusAdapterContext instance. Because the ComPlusAdapterContext class takes care of the database
	connection creation, the COM+ context held by the ComPlusAdapterContext will make sure that any database activity which uses the connection objects created by the
	ComPlusAdapterContext class are monitored by COM+ (the MS DTC service).
	
	The ComPlusAdapterContext class is just one example how COM+ can be used together with Adapter. You can also create your own class, deriving from 
	ComPlusAdapterContextBase and add different EnterpriseServices attributes to it to enable different services offered by COM+, like Just-In-Time activation or
	object pooling. Also you can for example grab the connection string from the COM+ object definition defined in Windows' Component Services. 
	
	Because COM+ is implemented in .NET using Enterprise Services, the class 
using the ComPlusAdapterContext object has to derive from
	ServicedComponent. This way, transactions started outside the class using the ComPlusAdapterContext class can flow through to the ComPlusAdapterContext
	class to the actions performed by the DataAccessAdapter object inside the ComPlusAdapterContext object. Also, you have to reference the 
	System.EnterpriseServices namespace in your code. Below is a short example how a COM+ transaction
	flows through to a ServicedComponent derived class and the code inside the TestComPlus() method will be running inside the COM+ transaction. When no
	COM+ transaction is available, a new one is created.
	
    
      
      
        // [C#]
[Transaction(TransactionOption.Required)]
public class TestClass : ServicedComponent
{
	[AutoComplete]
	public void TestComPlus()
	{
		ComPlusAdapterContext comPlusContext = new ComPlusAdapterContext();
		IDataAccessAdapter adapter = comPlusContext.Adapter;
		try
		{
			// start transaction. 
			adapter.StartTransaction(IsolationLevel.ReadCommitted, "ComPlusTran");
			CustomerEntity customer = new CustomerEntity("CHOPS");
			OrderEntity order = new OrderEntity(10254);
			adapter.FetchEntity(customer);
			adapter.FetchEntity(order);
			
			// alter the entities
			customer.Fax = "12345678";
			order.Freight = 12;
			
			// save the two entities again.
			adapter.SaveEntity(customer);
			adapter.SaveEntity(order);
			
			// done
			adapter.Commit();
		}
		catch
		{
			// abort
			adapter.Rollback();
			throw;
		}
		finally
		{
			comPlusContext.Dispose();
			((DataAccessAdapter)adapter).Dispose();
		}
	}
} 
        ' [VB.NET]
<Transaction(TransactionOption.Required)> _
Public Class TestClass 
	Inherits ServicedComponent
	<AutoComplete> _
	Public Sub TestComPlus()
		Dim comPlusContext As New ComPlusAdapterContext()
		Dim adapter As IDataAccessAdapter = comPlusContext.Adapter
		Try
			' start transaction. 
			adapter.StartTransaction(IsolationLevel.ReadCommitted, "ComPlusTran")
			Dim customer As New CustomerEntity("CHOPS")
			Dim order As New OrderEntity(10254)
			adapter.FetchEntity(customer)
			adapter.FetchEntity(order)
			
			' alter the entities
			customer.Fax = "12345678"
			order.Freight = 12
			
			' save the two entities again.
			adapter.SaveEntity(customer)
			adapter.SaveEntity(order)
			
			' done
			adapter.Commit()
		Catch
			' abort
			adapter.Rollback()
			Throw
		Finally
			comPlusContext.Dispose();
			((DataAccessAdapter)adapter).Dispose();
		End Try
	End Sub
End Class 
       
   
	
	
	
    	
        	  Note:
         | 
    
    
        | 
        	COM+ transactions are considered 'advanced material' in .NET applications. Use them with care. You have to give your assemblies a strong name
	and your application will cause extra overhead on your machine: every serviced component has a context in the COM+ service. Most of the time you can
	fulfill your transactional requirements using native database transactions with the normal ADO.NET transactions provided by the DataAccessAdapter, as
	illustrated in the previous section.
         | 
    
	
  
  .NET 2.0: System.Transactions support
	.NET 2.0 introduces the System.Transactions namespace. This is a namespace with the TransactionScope class, which eases the creation of distributed transactions,
	specifying a given scope. All transactions, for example normal ADO.NET transactions, are automatically elevated to distributed transactions, if required, by the 
	TransactionScope they're declared in. This requires support by the used database system as the database system has to be able to 
promote a non-distributed
	transaction to a distributed transaction. When .NET 2.0 shipped, only SqlServer 2005 was able to promote transactions to distributed transactions using
	System.Transactions' classes.
	
	
	The developer can define such a TransactionScope using the normal .NET constructs, like 
using(TransactionScope scope = new TransactionScope())
{
	// your code here.
}
	
	A DataAccessAdapter object is able to determine if it's participating inside an ambient transaction of
	System.Transactions. If so, it enlists a Resource Manager with the System.Transactions transaction. The Resource manager contains the 
	DataAccessAdapter object. As soon as a Transaction or DataAccessAdapter is enlisted through a Resource Manager, the Commit() and Rollback() methods
	are setting the ResourceManager's commit/abort signal which is requested by the System.Transactions' Transaction manager. If multiple transactions are executed 
	on a DataAccessAdapter and one rolled back,	the resource manager will report an abort. As soon as the DataAccessAdapter is enlisted in the
	System.Transactions.Transaction, no ADO.NET transaction is
	started, it's a no-op. Once one rollback is requested, the transaction will always report a rollback to the MSDTC.	
	
	
Going out of scope
	When the System.Transactions transaction is committed or rolled back, the Resource manager is notified and will then notify the DataAccessAdapter
	that it can commit/rollback the transaction. That call will then notify the enlisted entities of the outcome of the transaction. 
	
Multiple transactions executed using a single DataAccessAdapter object
	For the DataAccessAdapter it will look like its still inside the same transaction, so no new transaction is started. This will make sure that an entity which 
	is already participating in the transaction isn't enlisted again and the field values aren't saved again etc. 
	
	
Example
	Below is an example which shows the usage of a TransactionScope in combination of a DataAccessAdapter object. The code contains Assert statements to
	illustrate the state / outcome of the various statements.
  
  
     // C#
CustomerEntity newCustomer = new CustomerEntity();
// fill newCustomer's fields.
// ..
AddressEntity newAddress = new AddressEntity();
// fill newAddress' fields.
// ..
// start the scope.
using( TransactionScope ts = new TransactionScope() )
{
	// as we're inside the transaction scope, we can now create a DataAccessAdapter object and
	// start a connection + transaction. The connection + transaction will be enlisted through a 
	// resource manager in the TransactionScope ts and will be controlled by that TransactionScope.
	using(DataAccessAdapter adapter = new DataAccessAdapter())
	{
		// save 2 entities non-recursive. This should be done in one 
		// transaction, namely the transaction scope we've started. 
		newCustomer.VisitingAddress = newAddress;
		newCustomer.BillingAddress = newAddress;
		Assert.IsTrue( adapter.SaveEntity( newCustomer, true) );
		
		// save went well, alter the entities, which are fetched back, and 
		// save again.
		newCustomer.CompanyEmailAddress += " ";
		newAddress.StreetName += " ";
		Assert.IsTrue( adapter.SaveEntity( newCustomer, true ) );
	}
	// do not call Complete, as we want to rollback the transaction and see if the rollback indeed succeeds.
	// as the TransactionScope goes out of scope, the on-going transaction is rolled back.
}
// at this point the transaction of the previous using block is rolled back.
// let the DTC and the system.transactions threads deal with the objects. 
// this sleep is only needed because we're going to access the data directly after the rollback. In normal code, 
// this sleep isn't necessary.
Thread.Sleep( 1000 );
// test if the data is still there. Shouldn't be as the transaction has been rolled back. 
using( DataAccessAdapter adapter = new DataAccessAdapter() )
{
	CustomerEntity fetchedCustomer = new CustomerEntity( newCustomer.CustomerId );
	Assert.IsFalse( adapter.FetchEntity( fetchedCustomer ) );
	AddressEntity fetchedAddress = new AddressEntity( newAddress.AddressId );
	Assert.IsFalse( adapter.FetchEntity( fetchedAddress ) );
	Assert.AreEqual( 0, newAddress.AddressId );
} 
     ' VB.NET
Dim NewCustomer As New CustomerEntity()
' fill NewCustomer's fields.
' ..
Dim NewAddress As New AddressEntity()
' fill NewAddress' fields.
' ..
' start the scope.
Using  ts As New TransactionScope() 
	' as we're inside the transaction scope, we can now create a DataAccessAdapter object and
	' start a connection + transaction. The connection + transaction will be enlisted through a 
	' resource manager in the TransactionScope ts and will be controlled by that TransactionScope.
	Using adapter As New DataAccessAdapter()
		' save 2 entities non-recursive. This should be done in one 
		' transaction, namely the transaction scope we've started. 
		NewCustomer.VisitingAddress = NewAddress
		NewCustomer.BillingAddress = NewAddress
		Assert.IsTrue( adapter.SaveEntity( NewCustomer, True) )
		
		' save went well, alter the entities, which are fetched back, and 
		' save again.
		NewCustomer.CompanyEmailAddress = NewCustomer.CompanyEmailAddress & " "
		NewAddress.StreetName = NewAddress.StreetName & " "
		Assert.IsTrue( adapter.SaveEntity( NewCustomer, True ) )
	End Using
	' do not call Complete, as we want to rollback the transaction and see if the rollback indeed succeeds.
	' as the TransactionScope goes out of scope, the on-going transaction is rolled back.
End Using
' at this point the transaction of the previous using block is rolled back.
' let the DTC and the system.transactions threads deal with the objects. 
' this sleep is only needed because we're going to access the data directly after the rollback. In normal code, 
' this sleep isn't necessary.
Thread.Sleep( 1000 )
' test if the data is still there. Shouldn't be as the transaction has been rolled back. 
Using adapter As New DataAccessAdapter()
	Dim fetchedCustomer As New CustomerEntity( NewCustomer.CustomerId )
	Assert.IsFalse( adapter.FetchEntity( fetchedCustomer ) )
	Dim fetchedAddress = New AddressEntity( NewAddress.AddressId )
	Assert.IsFalse( adapter.FetchEntity( fetchedAddress ) )
	Assert.AreEqual( 0, NewAddress.AddressId )
End Using